package brian.android.view;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import brian.android.view.listener.OnScrollChangeListener;

public class ExtScrollView extends ScrollView {
	private static final int CRITICAL_X_POINT = 100;
	private static final int CRITICAL_Y_POINT = 70;
	private static final int CRITICAL_DISTANCE = 20;
	
	private int screenWidth;
	private int screenHeight;
	private int screenTopPadding;
	
	/** 현재 x 위치 */
	private int curXPos;
	
	/** 스크롤이 시작된 x 위치 */
	private int startX;
	
	/** 스크롤이 시작된 y 위치 */
	private int startY;
	
	/** x 축으로 움직였는지 여부  */
	private boolean isMoveX;
	
	/** 스크롤이 될 만큼 움직였는지 여부 */
	private boolean fMove = false;
	
	/** 초기화 되었는지 여부 */
	private boolean onStart = true;
	
	private GestureDetector gestureDetector;
	private LinearLayout mainLayout;
	private OnScrollChangeListener onLineChangeListener;
	private List<View> views = new ArrayList<View>();
	
	public ExtScrollView(Context context) {
		this(context, null);
	}
	
	public ExtScrollView(Context context, AttributeSet attributeSet) {
		super(context, attributeSet);
	}
	
	public void initViewer(Context context) {
		mainLayout = new LinearLayout(context);
		mainLayout.setOrientation(LinearLayout.HORIZONTAL);
		addView(mainLayout);
		
		gestureDetector = new GestureDetector(context, new SlideGestureListener());
		setHorizontalScrollBarEnabled(false);
		setVerticalScrollBarEnabled(false);
	}
	
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		screenHeight = b - t;
		screenWidth = r - l;
		screenTopPadding = screenHeight / 2;
		
		onLayoutSize();
		extScroll();
		if (onStart) {
			onLineChangeListener.onScrollViewInit(this);
			onStart = false;
		}
	}

	private void onLayoutSize() {
		int marginAddedScreenHeight = screenHeight * 2;
		
		mainLayout.setLayoutParams(new FrameLayout.LayoutParams(screenWidth * views.size(), marginAddedScreenHeight));
		for (View view : views) {
			view.setPadding(0, screenTopPadding, 0, screenTopPadding);
			view.setLayoutParams(new LinearLayout.LayoutParams(screenWidth, marginAddedScreenHeight));
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		
		switch (action) {
		case MotionEvent.ACTION_DOWN :
			startX = getScrollX();
			startY = getScrollY();
			break;
		case MotionEvent.ACTION_UP :
			if (fMove) {
				if (isMoveX) {
					extScrollXPos(getChangeXAmount());
				} else {
					extScrollYPos(getChangeYAmount());
				}
			}
			fMove = false;
			break;
		}
		
		gestureDetector.onTouchEvent(ev);
		return true;
	}

	private void extScrollYPos(int changeYPos) {
		if (changeYPos > 0) {
			onLineChangeListener.onScrollUp(this);
		} else if (changeYPos < 0) {
			onLineChangeListener.onScrollDown(this);
		}
		extScrollTo(curXPos);
	}

	private void extScrollXPos(int changeXPos) {
		// min, max를 벗어날 일은 없지만 만약의 오작동 대비 
		curXPos = Math.min(Math.max(0, curXPos + changeXPos), views.size() - 1);
		if (changeXPos > 0) {
			onLineChangeListener.onScrollRight(this);
		} else if (changeXPos < 0) {
			onLineChangeListener.onScrollLeft(this);
		}
		extScrollTo(curXPos);
	}

	public void extScroll() {
		extScrollTo(curXPos);
	}
	
	private void extScrollTo(int curXPos) {
		scrollTo(screenWidth * curXPos, screenTopPadding);
	}

	private int getChangeYAmount() {
		return getChageAmount(getScrollY(), startY, CRITICAL_Y_POINT);
	}

	private int getChangeXAmount() {
		return getChageAmount(getScrollX(), startX, CRITICAL_X_POINT);
	}
	
	private int getChageAmount(int start, int end, int criticalSize) {
		int moveAmount = start - end;
		int absMoveAmount = Math.abs(moveAmount);
		
		if (absMoveAmount > criticalSize) {
			if (moveAmount > 0) {
				return 1;
			} else {
				return -1;
			}
		} else {
			return 0;
		}
	}
	
	public void setOnSchollChangeListener(OnScrollChangeListener listener) {
		this.onLineChangeListener = listener;
	}
	
	public int getCurXPos() {
		return curXPos;
	}

	public void setViewLayouts(int ...layoutIds) {
		LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		for (int layoutId : layoutIds) {
			View view = layoutInflater.inflate(layoutId, null);
			views.add(view);
			mainLayout.addView(view);
		}
	}
	
	public List<View> getViews() {
		return views;
	}
	
	public View getViewAt(int idx) {
		return views.get(idx);
	}
	
	class SlideGestureListener implements android.view.GestureDetector.OnGestureListener {
		@Override
		public boolean onDown(MotionEvent e) {
			return false;
		}
		
		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
			return false;
		}
		
		@Override
		public void onLongPress(MotionEvent e) {
		}
		
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
			if (!fMove) {
				float absX = Math.abs(distanceX);
				float absY = Math.abs(distanceY);
				
				if (absX >= CRITICAL_DISTANCE) { 
					isMoveX = true;
					fMove = true;
				} else if (absY >= CRITICAL_DISTANCE) {
					isMoveX = false;
					fMove = true;
				}
			} else {
				if (isMoveX) {
					smoothScrollBy((int) distanceX, 0);
				} else {
					smoothScrollBy(0, (int) distanceY);
				}
			}
			return true;
		}

		@Override
		public void onShowPress(MotionEvent e) {
		}
		
		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			return false;
		}
	}
}
